﻿using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using Raider.WinForms.Actions.Linkage;

namespace Raider.WinForms.Actions
{
    /// <summary>
    /// Represents the action with the number of properties that is common for Windows Forms controls.
    /// </summary>
    /// <remarks>
    /// List of the supported client controls and components:
    /// <list type="bullet">
    /// <item><see cref="Control"/></item>
    /// <item><see cref="ButtonBase"/></item>
    /// <item><see cref="ToolStripItem"/></item>
    /// <item><see cref="MenuItem"/></item>
    /// </list>
    /// </remarks>
    [DefaultProperty("Title"), DefaultEvent("Execute"), Designer(Constants.ActionDesigner)]
    public class ControlAction : AsyncAction
    {
        private readonly string defaultCategory;
        private string category;

        private readonly Keys defaultShortcutKeys;
        private Keys shortcutKeys;

        private readonly Image defaultImage;
        private Image image;

        private string toolTip = "";
        private bool visible = true;
        private bool isChecked;
        private bool autoCheck;
        private object tag;

        /// <summary>
        /// Initializes a new instance of the <see cref="ControlAction"/> with the default values.
        /// </summary>
        public ControlAction()
        {
            this.defaultCategory = "";
            this.category = "";
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ControlAction"/>.
        /// </summary>
        /// <param name="title">Default title for the action (empty by default).</param>
        /// <param name="category">Default category for the action (empty by default).</param>
        /// <param name="shortcut">Default shortcut for the action (none by default).</param>
        /// <param name="image">Default image for the action (<c>null</c> by default).</param>
        public ControlAction(string title = "", string category = "", Keys shortcut = Keys.None, Image image = null)
            : base(title)
        {
            this.defaultCategory = category ?? "";
            this.category = category ?? "";
            this.defaultShortcutKeys = shortcut;
            this.shortcutKeys = shortcut;
            this.defaultImage = image;
            this.image = image;
        }

        /// <summary>
        /// Used to categorize actions in the designer.
        /// </summary>
        /// <value>Action's category, or <see cref="string.Empty"/> if category is not set.</value>
        [Bindable(false)]
        [Category("Data"), Description("Used to categorize actions in the designer.")]
        public string Category
        {
            get { return category; }
            set 
            {
                var newValue = value ?? "";
                if (category != newValue) 
                {
                    category = newValue;
                    OnPropertyChanged("Category"); 
                }
            }
        }

        /// <summary>
        /// Gets or sets a short description of the action.
        /// </summary>
        /// <value>Action's short description, or <see cref="string.Empty"/> if short description is not set.</value>
        [Localizable(true)]
        [DefaultValue(null)]
        [Category("Appearance"), Description("Defines the hint text of the action.")]
        [LinkWithProperty("ToolTipText", typeof(ToolStripItem))]
        public string ToolTip
        {
            get { return toolTip; }
            set
            {
                var newValue = value ?? "";
                if (toolTip != newValue)
                {
                    toolTip = newValue;
                    OnPropertyChanged("ToolTip");
                }
            }
        }

        /// <summary>
        /// Gets or sets the image to be displayed on the controls that support images.
        /// </summary>
        [Category("Appearance"), Description("Defines the icon to be displayed on the client controls and menu items.")]
        [LinkWithProperty("Image", typeof(ToolStripItem), typeof(ButtonBase))]
        public Image Image
        {
            get { return image; }
            set
            {
                if (image != value)
                {
                    image = value;
                    OnPropertyChanged("Image");
                }
            }
        }

        /// <summary>
        /// Gets or sets the keyboard shortcut associated with the action.
        /// </summary>
        [Category("Behavior"), Description("Keyboard shortcut associated with the action.")]
        [LinkWithProperty("ShortcutKeys", typeof(ToolStripMenuItem))]
        public Keys ShortcutKeys
        {
            get { return shortcutKeys; }
            set
            {
                if (shortcutKeys != value)
                {
                    shortcutKeys = value;
                    OnPropertyChanged("ShortcutKeys");
                }
            }
        }

        /// <summary>
        /// Gets or sets the value, indicating whether the controls linked with this Action
        /// should appear checked.
        /// </summary>
        [DefaultValue(false)]
        [Category("Behavior"), Description("Indicates whether client controls and menu items appear checked.")]
        [LinkWithProperty("Checked", typeof(ToolStripMenuItem), typeof(ToolStripButton), 
                                     typeof(MenuItem), typeof(CheckBox), typeof(RadioButton))]
        public bool Checked
        {
            get { return isChecked; }
            set
            {
                if (isChecked != value)
                {
                    isChecked = value;
                    OnPropertyChanged("Checked");
                }
            }
        }

        /// <summary>
        /// Gets or sets the value, indicating whether the controls linked with this Action
        /// are visible.
        /// </summary>
        [DefaultValue(true)]
        [Category("Behavior"), Description("Indicates whether the action's representation is visible.")]
        [LinkWithProperty("Visible", typeof(ToolStripItem), typeof(MenuItem), typeof(Control))]
        public bool Visible
        {
            get { return visible; }
            set
            {
                if (visible != value)
                {
                    visible = value;
                    OnPropertyChanged("Visible");
                }
            }
        }

        /// <summary>
        /// Gets or sets the value, indicating whether the <see cref="Checked"/> property should be toggled
        /// when this Action executes.
        /// </summary>
        [DefaultValue(false)]
        [Category("Behavior"), Description("Controls whether the Checked property toggles when action executes.")]
        public bool AutoCheck
        {
            get { return autoCheck; }
            set
            {
                if (autoCheck != value)
                {
                    autoCheck = value;
                    OnPropertyChanged("AutoCheck");
                }
            }
        }

        /// <summary>
        /// Gets or sets the user-defined data associated with the Action.
        /// </summary>
        [DefaultValue(null)]
        [Category("Data"), Description("User-defined data associated with the action."), TypeConverter(typeof(StringConverter))]
        public object Tag
        {
            get { return tag; }
            set
            {
                if (tag != value)
                {
                    tag = value;
                    OnPropertyChanged("Tag");
                }
            }
        }

        protected override void OnExecuting(ExecutingEventArgs args)
        {
            base.OnExecuting(args);

            // Toogle Checked property.
            if (!args.Cancel && AutoCheck)
            {
                Checked = !Checked;
            }
        }

        #region Required for VS designer

        /// <summary>
        /// Resets a value of <see cref="Category"/> property.
        /// </summary>
        public void ResetCategory()
        {
            Category = defaultCategory;
        }

        /// <summary>
        /// Resets a value of <see cref="ShortcutKeys"/> property.
        /// </summary>
        public void ResetShortcutKeys()
        {
            ShortcutKeys = defaultShortcutKeys;
        }

        /// <summary>
        /// Resets a value of <see cref="Image"/> property.
        /// </summary>
        public void ResetImage()
        {
            Image = defaultImage;
        }

        protected bool ShouldSerializeCategory()
        {
            return Category != defaultCategory;
        }

        protected bool ShouldSerializeShortcutKeys()
        {
            return ShortcutKeys != defaultShortcutKeys;
        }

        protected bool ShouldSerializeImage()
        {
            return Image != defaultImage;
        }

        #endregion
    }
}
